package com.zego.example.videoplayerdemo.utils;

import ohos.agp.graphics.Surface;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.common.Source;
import ohos.media.common.sessioncore.AVElement;
import ohos.media.player.Player;

import java.util.Timer;
import java.util.TimerTask;

public class VideoPlayerPlugin {
    private static final String TAG = VideoPlayerPlugin.class.getSimpleName();

    private final Context context;

    private Player videoPlayer;

    private Runnable videoRunnable;

    private VideoPlayerEventHandler eventHandler;

    private Timer timer;
    private PlaybackState playbackState;

    public VideoPlayerPlugin(Context sliceContext) {
        context = sliceContext;
    }

    public synchronized void setVideoPlayerEventHandler(VideoPlayerEventHandler handler) {
        eventHandler = handler;
    }

    public synchronized void play(AVElement avElement, Surface surface) {
        if (videoPlayer != null) {
            // release 会重置播放状态并关闭定时器
            videoPlayer.stop();
            videoPlayer.release();
            videoPlayer = null;
        }

        if (videoRunnable != null) {
            ThreadPoolManager.getInstance().cancel(videoRunnable);
        }

        videoPlayer = new Player(context);
        setPlayerCallback();

        videoRunnable = () -> playInner(avElement, surface);
        ThreadPoolManager.getInstance().execute(videoRunnable);
        LogUtil.info(TAG, "play");
    }

    public synchronized void pause() {
        if (videoPlayer == null) {
            return;
        }
        videoPlayer.pause();
        playbackState = PlaybackState.VIDEO_PLAYER_PAUSING;
        endTimer();
        LogUtil.info(TAG, "pause");
    }

    public synchronized void resume() {
        if (videoPlayer == null) {
            return;
        }
        videoPlayer.play();
        playbackState = PlaybackState.VIDEO_PLAYER_PLAYING;
        startTimer();
        LogUtil.info(TAG, "resume");
    }

    public synchronized void updateSurface(Surface surface) {
        if (videoPlayer == null) {
            return;
        }
        videoPlayer.setVideoSurface(surface);
    }

    public synchronized int getDuration() {
        if (videoPlayer == null) {
            return 0;
        }

        return videoPlayer.getDuration();
    }

    public synchronized void seekTo(long millisecond) {
        if (videoPlayer == null) {
            return;
        }

        // 注意，rewindTo 接口参数单位是微秒
        videoPlayer.rewindTo(millisecond * 1000);
        LogUtil.info(TAG, "seek" + videoPlayer.getCurrentTime());
    }

    public synchronized void setPlaybackVolume(int volume) {
        if (videoPlayer == null) {
            return;
        }

        videoPlayer.setVolume((float) ((float) volume/100.0));
    }

    public synchronized void setPlaybackSpeed(float speed) {
        if (videoPlayer == null) {
            return;
        }

        videoPlayer.setPlaybackSpeed(speed);
    }

    public synchronized float getPlaybackSpeed() {
        if (videoPlayer == null) {
            return 0.0f;
        }

        return videoPlayer.getPlaybackSpeed();
    }

    public void release() {
        playbackState = PlaybackState.VIDEO_PLAYER_NO_PLAY;
        endTimer();
        if (videoPlayer != null) {
            videoPlayer.stop();
            videoPlayer.release();
            videoPlayer = null;
        }
    }

    private void playInner(AVElement avElement, Surface surface) {
        Source source = new Source(avElement.getAVDescription().getMediaUri().toString());
        videoPlayer.setSource(source);
        videoPlayer.setVideoSurface(surface);
        LogUtil.info(TAG, source.getUri());

        videoPlayer.prepare();
        videoPlayer.play();
        playbackState = PlaybackState.VIDEO_PLAYER_PLAYING;
        startTimer();
    }

    private void startTimer() {
        if (timer == null) {
            timer = new Timer("PlaybackPorgressTimer");
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    playbackProgressUpdate();
                }
            }, 200L, 200L);
        }
    }

    private void endTimer() {
        if (timer == null) {
            return;
        }
        timer.cancel();
        timer = null;
    }

    private void playbackProgressUpdate() {
        if (eventHandler == null || videoPlayer == null) {
            return;
        }
        int currentPlaybackProgress = videoPlayer.getCurrentTime();
        EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
        handler.postTask(new Runnable() {
            @Override
            public void run() {
                eventHandler.onPlaybackProgressUpdate(currentPlaybackProgress);
            }
        });
    }

    private void setPlayerCallback() {
        videoPlayer.setPlayerCallback(new Player.IPlayerCallback() {
            @Override
            public void onPrepared() {
                if (eventHandler == null) {
                    return;
                }
                EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
                handler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        eventHandler.onPrepared();
                    }
                });
            }

            @Override
            public void onMessage(int type, int extra) {
                if (eventHandler == null) {
                    return;
                }
                EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
                handler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        eventHandler.onMessage(type, extra);
                    }
                });
            }

            @Override
            public void onError(int errorType, int errorCode) {
                if (eventHandler == null) {
                    return;
                }
                EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
                handler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        eventHandler.onError(errorType, errorCode);
                    }
                });
            }

            @Override
            public void onResolutionChanged(int width, int height) {
                if (eventHandler == null) {
                    return;
                }
                EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
                handler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        eventHandler.onResolutionChanged(width, height);
                    }
                });
            }

            @Override
            public void onPlayBackComplete() {
                playbackState = PlaybackState.VIDEO_PLAYER_PLAY_ENDED;
                endTimer();
                if (eventHandler == null) {
                    return;
                }
                EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
                handler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        eventHandler.onPlayBackComplete();
                    }
                });
            }

            @Override
            public void onRewindToComplete() {
                if (eventHandler == null) {
                    return;
                }
                EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
                handler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        eventHandler.onRewindToComplete();
                    }
                });
            }

            @Override
            public void onBufferingChange(int percent) {
                if (eventHandler == null) {
                    return;
                }
                EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
                handler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        eventHandler.onBufferingChange(percent);
                    }
                });
            }

            @Override
            public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData) {
                if (eventHandler == null) {
                    return;
                }
                EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
                handler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        eventHandler.onNewTimedMetaData(mediaTimedMetaData);
                    }
                });
            }

            @Override
            public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo) {
                if (eventHandler == null) {
                    return;
                }
                EventHandler handler = new EventHandler(EventRunner.getMainEventRunner());
                handler.postTask(new Runnable() {
                    @Override
                    public void run() {
                        eventHandler.onMediaTimeIncontinuity(mediaTimeInfo);
                    }
                });
            }
        });
    }

    enum PlaybackState {
        VIDEO_PLAYER_NO_PLAY,
        VIDEO_PLAYER_PLAYING,
        VIDEO_PLAYER_PAUSING,
        VIDEO_PLAYER_PLAY_ENDED
    }

    public interface VideoPlayerEventHandler {
        public void onPrepared();
        public void onPlaybackProgressUpdate(int millisecond);
        public void onMessage(int type, int extra);
        public void onError(int errorType, int errorCode);
        public void onResolutionChanged(int width, int height);
        public void onPlayBackComplete();
        public void onRewindToComplete();
        public void onBufferingChange(int percent);
        public void onNewTimedMetaData(Player.MediaTimedMetaData mediaTimedMetaData);
        public void onMediaTimeIncontinuity(Player.MediaTimeInfo mediaTimeInfo);
    }
}
